package com.ywu.application.standard.appManage.service;

import com.ywu.application.standard.adminUser.entity.UserEntity;
import com.ywu.application.standard.adminUser.service.UserService;
import com.ywu.application.standard.appManage.config.AppManageConfig;
import com.ywu.application.standard.appManage.data.YwuAppRepository;
import com.ywu.application.standard.appManage.dto.YwuAppDto;
import com.ywu.application.standard.appManage.dto.YwuAppUserDto;
import com.ywu.application.standard.appManage.dto.YwuOpenServiceDto;
import com.ywu.application.standard.appManage.entity.YwuAppEntity;
import com.ywu.application.standard.appManage.entity.YwuAppUserEntity;
import com.ywu.boot.config.BootConfigAppConfig;
import com.ywu.boot.context.YwuContext;
import com.ywu.boot.context.YwuContextApp;
import com.ywu.boot.context.YwuContextHolder;
import com.ywu.boot.context.YwuContextUser;
import com.ywu.boot.exception.YwuRuntimeException;
import com.ywu.common.constant.CommonConstant;
import com.ywu.common.entity.PageList;
import com.ywu.common.gson.GsonUtils;
import com.ywu.common.page.PageService;
import com.ywu.common.result.CommonResult;
import com.ywu.common.utils.AesUtils;
import com.ywu.common.utils.JwtUtils;
import com.ywu.common.utils.TimerIdGenerateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName YwuAppService
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/7/29 19:29
 * @Version 1.0
 **/
@Service
@Slf4j
public class YwuAppService {
    @Autowired
    private YwuAppRepository repository;

    @Autowired
    private YwuAppUserService ywuAppUserService;

    @Autowired
    private UserService userService;

    @Autowired
    private AppManageConfig appConfig;

    @Autowired
    private BootConfigAppConfig bootConfigAppConfig;

    /**
    * @Author GroundDemo
    * @Description 分页查询
    * @Date 19:33 2024/7/29
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> appQueryPageList(YwuAppDto ywuAppDto) {
        // 查询数量
        int count = repository.queryPageCount(ywuAppDto);
        // 构建分页参数
        PageService.execPageStartAndEnd(ywuAppDto.getPageInfo());
        // 分页查询
        List<YwuAppEntity> ywuAppEntities = repository.queryPageList(ywuAppDto);
        // 如果为空的话直接返回
        if (CollectionUtils.isEmpty(ywuAppEntities)) {
            return CommonResult.success(new PageList<>(ywuAppDto.getPageInfo().getPageIndex(),
                    ywuAppDto.getPageInfo().getPageSize(), 0, new ArrayList<>()));
        }
        // 查询用户信息
        List<Integer> userIds = ywuAppEntities.stream().map(YwuAppEntity::getAppOwner).collect(Collectors.toList());
        CommonResult<List<UserEntity>> queryRes = userService.queryUserByUserIdBatch(userIds);
        if (Objects.isNull(queryRes) || !"200".equals(queryRes.getCode())) {
            throw new YwuRuntimeException("user.info.query.error");
        }
        // 根据查询结果进行拼装
        List<UserEntity> data = queryRes.getData();
        Map<Integer, UserEntity> userMap = data.stream().collect(Collectors.toMap(UserEntity::getId, Function.identity()));
        for (YwuAppEntity entity : ywuAppEntities) {
            // 根据用户ID进行匹配用户账号
            if (userMap.containsKey(entity.getAppOwner())) {
                UserEntity userEntity = userMap.get(entity.getAppOwner());
                entity.setAppOwnerAccount(userEntity.getUserAccount());
            }
        }
        // 构建分页对象
        PageList<YwuAppEntity> pageList = new PageList<>(ywuAppDto.getPageInfo().getPageIndex(), ywuAppDto.getPageInfo().getPageSize(),
                count, ywuAppEntities);
        return CommonResult.success(pageList);
    }

    /**
    * @Author GroundDemo
    * @Description 创建应用
    * @Date 19:34 2024/7/29
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    @Transactional
    public CommonResult<Object> appCreateInfo(YwuAppDto ywuAppDto) {
        // 判断token是否存在，如果不存在返回400
        if (StringUtils.isEmpty(ywuAppDto.getAppToken())) {
            return CommonResult.error().setErrorCode("ywu.app.token.is.empty")
                    .setMessage("appToken不能为空");
        }
        // 校验appId是否存在
        YwuAppEntity searchEntity = new YwuAppEntity();
        searchEntity.setAppId(ywuAppDto.getAppId());
        YwuAppEntity entity = repository.getEntity(searchEntity);
        if (Objects.nonNull(entity)) {
            return CommonResult.error().setErrorCode("ywu.app.id.is.exist")
                    .setMessage("appId已存在");
        }
        // 对appToken进行加密
        String encrypt = "";
        try {
            encrypt = AesUtils.encrypt(ywuAppDto.getAppToken(), appConfig.getSecretKey());
        } catch (Exception e) {
            log.error("appCreateInfo encrypt error");
            return CommonResult.error().setErrorCode("encrypt.error")
                    .setMessage("appToken加密失败");
        }
        // 构建插入对象
        YwuAppEntity ywuAppEntity = new YwuAppEntity();
        BeanUtils.copyProperties(ywuAppDto, ywuAppEntity);
        // 设置ID
        ywuAppEntity.setId(TimerIdGenerateUtil.nextId());
        ywuAppEntity.createInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        ywuAppEntity.setAppToken(encrypt);
        // 插入数据
        repository.addAppInfo(ywuAppEntity);
        // 插入一条用户关联记录
        YwuAppUserDto ywuAppUserDto = new YwuAppUserDto();
        ywuAppUserDto.setAppId(ywuAppDto.getAppId());
        ywuAppUserDto.setUserId(ywuAppDto.getAppOwner());
        ywuAppUserService.appUserCreateInfo(ywuAppUserDto);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 修改应用信息
    * @Date 19:46 2024/7/29
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    @Transactional
    public CommonResult<Object> appUpdateInfo(YwuAppDto ywuAppDto) {
        // 判断修改后的AppId是否存在
        YwuAppEntity search = new YwuAppEntity();
        search.setAppId(ywuAppDto.getAppId());
        search.setId(ywuAppDto.getId());
        YwuAppEntity entity = repository.updateCheck(search);
        if (Objects.nonNull(entity)) {
            log.info("appUpdateInfo ywu.app.id.is.exist");
            return CommonResult.error().setErrorCode("ywu.app.id.is.exist")
                    .setMessage("appId已存在");
        }
        search.setAppId(null);
        YwuAppEntity entityInfo = repository.getEntity(search);
        // 判断该应用的管理员是否与已存在的一致，不一致的话需要删除原来的授权记录后重新添加
        if (!entityInfo.getAppOwner().equals(ywuAppDto.getAppOwner())) {
            ywuAppUserService.deleteByAppIdAndUserId(entityInfo.getAppId(), entityInfo.getAppOwner());
        }
        // 构建插入对象
        YwuAppEntity ywuAppEntity = new YwuAppEntity();
        BeanUtils.copyProperties(ywuAppDto, ywuAppEntity);
        ywuAppEntity.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        // 如果传入的appToken不为空，则进行token的加密
        if (StringUtils.isNotBlank(ywuAppDto.getAppToken())) {
            // 对appToken进行加密
            String encrypt = "";
            try {
                encrypt = AesUtils.encrypt(ywuAppDto.getAppToken(), appConfig.getSecretKey());
            } catch (Exception e) {
                log.error("appUpdateInfo encrypt error");
                return CommonResult.error().setErrorCode("encrypt.error")
                        .setMessage("appToken加密失败");
            }
            ywuAppEntity.setAppToken(encrypt);
        }
        repository.updateAppInfo(ywuAppEntity);
        // 兼容授权表的应用ID修改
        if (!StringUtils.equals(entityInfo.getAppId(), ywuAppDto.getAppId())) {
            // 批量修改原始应用ID为现有修改后的应用ID
            ywuAppUserService.updateAppIdByOriginAppId(entityInfo.getAppId(), ywuAppDto.getAppId());
        }
        if (!entityInfo.getAppOwner().equals(ywuAppDto.getAppOwner())) {
            // 添加新的应用授权
            YwuAppUserDto ywuAppUserDto = new YwuAppUserDto();
            ywuAppUserDto.setAppId(ywuAppDto.getAppId());
            ywuAppUserDto.setUserId(ywuAppDto.getAppOwner());
            ywuAppUserService.appUserCreateInfo(ywuAppUserDto);
        }
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 删除应用
    * @Date 20:10 2024/7/29
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    @Transactional
    public CommonResult<Object> appDeleteInfo(YwuAppDto ywuAppDto) {
        // 删除应用之前删除用户的关联关系
        ywuAppUserService.deleteByAppId(ywuAppDto.getAppId());
        YwuAppEntity ywuAppEntity = new YwuAppEntity();
        BeanUtils.copyProperties(ywuAppDto, ywuAppEntity);
        repository.deleteAppInfoById(ywuAppEntity);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 查询用户下的所有应用信息
    * @Date 21:04 2024/7/29
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<List<YwuAppEntity>> queryAppInfoByUser(YwuAppUserDto ywuAppUserDto) {
        // 根据用户ID查询用户所拥有的应用
        YwuAppUserDto search = new YwuAppUserDto();
        search.setUserId(ywuAppUserDto.getUserId());
        List<YwuAppEntity> ywuAppEntities = repository.queryAppInfoByUser(search);
        return CommonResult.success(ywuAppEntities);
    }

    /**
    * @Author GroundDemo
    * @Description 查询当前用户下的所有应用列表&当前登录的应用
    * @Date 12:00 2024/8/3
    * @Param []
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> queryCurrentAppInfo() {
        YwuContextUser ywuContextUser = YwuContextHolder.getCurrentContext().getYwuContextUser();
        // 查询当前用户所有的应用信息
        YwuAppUserDto search = new YwuAppUserDto();
        search.setUserId(ywuContextUser.getId());
        List<YwuAppEntity> ywuAppEntities = repository.queryAppInfoByUser(search);
        HashMap<String, Object> resMap = new HashMap<>();
        if (CollectionUtils.isEmpty(ywuAppEntities)) {
            resMap.put("currentApp", new YwuAppEntity());
            resMap.put("userAppList", new ArrayList<>());
            return CommonResult.success(resMap);
        }
        // 获取当前上下文中的应用信息
        YwuContextApp ywuContextApp = YwuContextHolder.getCurrentContext().getYwuContextApp();
        if (Objects.isNull(ywuContextApp) || StringUtils.isBlank(ywuContextApp.getAppId())) {
            resMap.put("currentApp", new YwuAppEntity());
            resMap.put("userAppList", new ArrayList<>());
            return CommonResult.success(resMap);
        } else {
            List<YwuAppEntity> collect = ywuAppEntities.stream().filter(res -> StringUtils.equals(res.getAppId(), ywuContextApp.getAppId())).collect(Collectors.toList());
            // 如果传入的appId不在用户的授权范围之内，则认定为前端非法传参，删除cookie
            YwuAppEntity entity = collect.get(0);
            resMap.put("currentApp", entity);
        }
        resMap.put("userAppList", ywuAppEntities);
        return CommonResult.success(resMap);
    }

    /**
    * @Author GroundDemo
    * @Description 用户选择应用切换
    * @Date 21:55 2024/8/4
    * @Param [ywuAppDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> changeCurrentUserAppInfo(YwuAppDto ywuAppDto, HttpServletResponse response) {
        // 判断前端传入的AppId是否为空
        if (StringUtils.isBlank(ywuAppDto.getAppId())) {
            return CommonResult.error().setErrorCode("appId.is.empty")
                    .setMessage("应用ID为空");
        }
        // 根据当前用户与租户ID查询授权
        YwuAppUserDto ywuAppUserDto = new YwuAppUserDto();
        ywuAppUserDto.setUserId(YwuContextHolder.getCurrentContext().getYwuContextUser().getId());
        ywuAppUserDto.setAppId(ywuAppUserDto.getAppId());
        YwuAppUserEntity ywuAppUserEntity = ywuAppUserService.getYwuAppUserEntity(ywuAppUserDto);
        if (Objects.isNull(ywuAppUserEntity) || StringUtils.isEmpty(ywuAppUserEntity.getId())) {
            return CommonResult.error().setErrorCode("user.has.not.app.permission")
                    .setMessage("用户无该应用的授权");
        }
        // 查询当前的应用信息，并生成token重新设置到cookie中
        YwuAppEntity entity = new YwuAppEntity();
        entity.setAppId(ywuAppDto.getAppId());
        YwuAppEntity ywuApp = repository.getEntity(entity);
        // 解密Token 的key
        String decryptTokenKey;
        try {
            decryptTokenKey = AesUtils.decrypt(bootConfigAppConfig.getTokenKey(), bootConfigAppConfig.getSecretKey());
        } catch (Exception e) {
            log.error("changeCurrentUserAppInfo decryptTokenKey error {}", e.getMessage());
            return CommonResult.error().setCode(CommonConstant.ERROR_CODE).setErrorCode("changeCurrentUserAppInfo.decrypt.error")
                    .setMessage("用户应用信息解密异常!");
        }
        // 生成token信息
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        String appInfoToken = JwtUtils.createAppInfoToken(currentContext.getYwuContextUser().getUserAccount(),
                GsonUtils.serialize(ywuApp),
                decryptTokenKey, appConfig.getAppInfoExpire());
        Cookie appInfoCookie = new Cookie("currentAppInfoKey", appInfoToken);
        appInfoCookie.setPath("/");
        response.addCookie(appInfoCookie);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 根据应用ID查询应用信息
    * @Date 20:47 2024/8/15
    * @Param [ywuAppUserDtoList]
    * @return com.ywu.common.result.CommonResult<java.util.List<com.ywu.app.manage.standard.entity.YwuAppEntity>>
    **/
    public CommonResult<List<YwuAppEntity>> queryAppInfoByAppId(List<YwuAppUserDto> ywuAppUserDtoList) {
        List<String> appIds = ywuAppUserDtoList.stream().map(YwuAppUserDto::getAppId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(appIds)) {
            return CommonResult.success(new ArrayList<>());
        }
        List<YwuAppEntity> entityList = repository.queryAppInfoByAppId(appIds);
        return CommonResult.success(entityList);
    }

    /**
    * @Author GroundDemo
    * @Description 查询所有应用
    * @Date 20:18 2024/8/16
    * @Param []
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> queryAllAppInfo() {
        List<YwuAppEntity> entityList = repository.queryAllAppInfo();
        return CommonResult.success(entityList);
    }

    /**
    * @Author GroundDemo
    * @Description appToken认证
    * @Date 11:02 2024/9/28
    * @Param [dto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> checkAppToken(YwuAppDto dto) {
        // 根据appId查询数据
        YwuAppEntity search = new YwuAppEntity();
        search.setAppId(dto.getAppId());
        YwuAppEntity queryEntity = repository.getEntityByAppId(search);
        // 解密数据
        String appToken = queryEntity.getAppToken();
        String decrypt = "";
        try {
            decrypt = AesUtils.decrypt(appToken, appConfig.getSecretKey());
        } catch (Exception e) {
            log.error("checkAppToken decrypt error");
            return CommonResult.error().setErrorCode("decrypt.error")
                    .setMessage("appToken解密失败");
        }
        // 校验解密后的token与传入的值是否一致
        if (StringUtils.equals(decrypt, dto.getAppToken())) {
            return CommonResult.success(null);
        } else {
            return CommonResult.error().setErrorCode("app.token.check.failed")
                    .setMessage("appToken校验失败");
        }
    }

    /**
    * @Author GroundDemo
    * @Description 获取openService的请求头token信息
    * @Date 12:03 2024/9/28
    * @Param [dto]
    * @return com.ywu.common.result.CommonResult<java.lang.String>
    **/
    public CommonResult<String> getOpenServiceToken(YwuOpenServiceDto dto) {
        String decryptTokenKey;
        try {
            decryptTokenKey = AesUtils.decrypt(bootConfigAppConfig.getTokenKey(), bootConfigAppConfig.getSecretKey());
        } catch (Exception e) {
            log.error("getOpenServiceToken decrypt error {}", e.getMessage());
            throw new YwuRuntimeException(e.getMessage());
        }
        String openServiceToken = JwtUtils.createOpenServiceToken(dto.getAppId(), dto.getAppToken(),
                dto.getSource(), decryptTokenKey, 3600000000L);
        return CommonResult.success(openServiceToken);
    }
}
